﻿using System.Threading;
using System.Windows;
//using System.Windows.Threading;
using personalplaner.common.mvvm;
using System.Windows.Input;
using personalplaner.common.mvvm.commands;
using System;
using System.Windows.Controls;
using System.Collections.Generic;
using personalplaner.databasewizard.views;
using personalplaner.databasewizard.viewmodels.models;
using personalplaner.databasewizard.services;
using personalplaner.common.mvvm.mediator;
using personalplaner.business.common;
using System.Collections.ObjectModel;
using personalplaner.common;

namespace personalplaner.databasewizard.viewmodels
{
    public class WizardWindowViewModel : BaseViewModel
	{
        public WizardWindowViewModel(DependencyObject parent)
			: base(parent)
		{
		}

        #region Commands

        #region General

        ICommand _okcommand;
        public ICommand OkCommand
        {
            get
            {
                if (_okcommand == null)
                    _okcommand = new RelayCommand(OnOkCommand, CanExecuteOk);
                return _okcommand;
            }
        }

        private void OnOkCommand(object parameter)
        {
            var wnd = Parent as Window;
            if (wnd == null)
                throw new Exception();

            // reset the logon information 
            // to set the new database as startup database
            var login = LoginData.Deserialize();
            if (login == null)
                login = new LoginData();
            login.Database = LogonModel.SelectedDatabase;
            login.DSN = LogonModel.SelectedOdbcSource;
            LoginData.Serialize(login);

            if (StartPersonalplanerOnClose)
            {
                if (System.IO.File.Exists(@"Personalplaner.exe"))
                {
                    // datenbankwizard starten damit die datenbank aktualisiert werden kann
                    var personalplaner = new System.Diagnostics.Process();
                    personalplaner.StartInfo.FileName = @"Personalplaner.exe";
                    personalplaner.StartInfo.Arguments = LogonModel.SelectedDatabase;
                    personalplaner.Start();
                }
            }

            //wnd.DialogResult = true;
            wnd.Close();
        }

        private bool CanExecuteOk(object parameter)
        {
            RaisePropertyChanged("IsEndOfWizard");
            return IsEndOfWizard && !IsExecutingScripts;
        }

        ICommand _cancelcommand;
        public ICommand CancelCommand
        {
            get
            {
                if (_cancelcommand == null)
                    _cancelcommand = new RelayCommand(OnCancelCommand, p => !IsExecutingScripts && !IsEndOfWizard && !IsScriptsExecuted);
                return _cancelcommand;
            }
        }

        private void OnCancelCommand(object parameter)
        {
            var wnd = Parent as Window;
            if (wnd == null)
                throw new Exception();

            //wnd.DialogResult = false;
            wnd.Close();
        }

        ICommand _nextcommand;
        public ICommand NextCommand
        {
            get
            {
                if (_nextcommand == null)
                    _nextcommand = new RelayCommand(OnNext, CanExecuteNext);
                return _nextcommand;
            }
        }

        private void OnNext(object parameter)
        {
            if (IsEndOfWizard)
                return;

            if (SelectedView is WelcomeView)
            {
            }
            else if (SelectedView is LogonView)
            {
                var da = GetService<IOdbcSourceService, OdbcSourceService>();
                if (!da.IsLoginValid(LogonModel.SelectedOdbcSource, LogonModel.User, LogonModel.Password))
                {
                    MessageBox.Show(personalplaner.databasewizard.Properties.Resources.IncorectSettings,
                        personalplaner.databasewizard.Properties.Resources.IncorectSettingsHeader,
                        MessageBoxButton.OK,
                        MessageBoxImage.Error);
                    return;
                }
            }
            else if (SelectedView is DatabaseInfoView)
            {
            }
            else if (SelectedView is StatusView)
            {
            }


            for (int i = 0; i < Views.Count; i++)
            {
                if (Views[i] == SelectedView)
                {
                    if (SelectedView is LogonView && !LogonModel.IsNewDatabase)
                        SelectedView = Views[i + 2];
                    else
                        SelectedView = Views[i + 1];
                    break;
                }
            }

            if (SelectedView is WelcomeView)
            {
            }
            else if (SelectedView is LogonView)
            {
            }
            else if (SelectedView is DatabaseInfoView)
            {
            }
            else if (SelectedView is StatusView)
            {
                ExecuteScripts();
            }
        }

        private bool CanExecuteNext(object parameter)
        {
            if (SelectedView == Views[4] || IsExecutingScripts)
                return false;

            if (SelectedView is WelcomeView)
            {
            }
            else if (SelectedView is LogonView)
            {
                if (!LogonModel.IsNewDatabase && string.IsNullOrEmpty(LogonModel.SelectedDatabase))
                    return false;
            }
            else if (SelectedView is DatabaseInfoView)
            {
                if (string.IsNullOrEmpty(LogonModel.SelectedDatabase))
                    return false;
            }
            else if (SelectedView is StatusView)
            {
            }

            return true;
        }

        ICommand _previouscommand;
        public ICommand PreviousCommand
        {
            get
            {
                if (_previouscommand == null)
                    _previouscommand = new RelayCommand(OnPrevious, parameter => SelectedView != Views[0] && !IsEndOfWizard && !IsScriptsExecuted);
                return _previouscommand;
            }
        }

        private void OnPrevious(object parameter)
        {
            for (int i = 0; i < Views.Count; i++)
            {
                if (Views[i] == SelectedView)
                {
                    if (SelectedView is StatusView && !LogonModel.IsNewDatabase)
                        SelectedView = Views[i - 2];
                    else
                        SelectedView = Views[i - 1];
                    break;
                }
            }
        }

        #endregion

        #endregion

        #region Implementation

        /// <summary>
        /// starts the execution of the update or creation scripts in a separate thread
        /// </summary>
        private void ExecuteScripts()
        {
            IsExecutingScripts = true;

            try
            {
                IDatabaseService service = null;
                if (LogonModel.IsNewDatabase)
                {
                    service = GetService<ICreateDatabaseService, CreateDatabaseService>();
                }
                else
                {
                    service = GetService<IUpdateDatabaseService, UpdateDatabaseService>();
                }

                service.Mediator.Register(StatusView);
                service.Mediator.Register(this);

                //service.Execute(LogonModel.SelectedOdbcSource, LogonModel.User, LogonModel.Password, LogonModel.SelectedDatabase)
                var workerThread = new Thread(
                    delegate()
                    {
                        Thread.Sleep(500);
                        service.Execute(LogonModel.SelectedOdbcSource, LogonModel.User, LogonModel.Password, LogonModel.SelectedDatabase);
                    });
                workerThread.Start();
            }
            catch (Exception)
            {
                IsExecutingScripts = false;
            }
        }

        [MediatorMessageSink("DatabaseExetueFinished")]
        public void DatabaseExetueFinished()
        {
            //delay
            //Thread.Sleep(1500);
            IsExecutingScripts = false;
            
            //enable buttons to move to next view
            //Controler.ButtonsEnabled = true;
            //Controler.MoveNext();
        }

        void LogonModelPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            var da = GetService<IOdbcSourceService, OdbcSourceService>();
            switch (e.PropertyName)
            {
                case "SelectedOdbcSource":
                    if (!LogonModel.IsNewDatabase)
                        LoadDatabases();
                    //LogonModel.Databases = da.GetDatabases(LogonModel.SelectedOdbcSource, LogonModel.User, LogonModel.Password);
                    break;
                case "Password":
                    if (!LogonModel.IsNewDatabase)
                        LoadDatabases();
                    //LogonModel.Databases = da.GetDatabases(LogonModel.SelectedOdbcSource, LogonModel.User, LogonModel.Password);
                    break;
                case "User":
                    if (!LogonModel.IsNewDatabase)
                        LoadDatabases();
                    //LogonModel.Databases = da.GetDatabases(LogonModel.SelectedOdbcSource, LogonModel.User, LogonModel.Password);
                    break;
                case "IsNewDatabase":
                    if (LogonModel.IsNewDatabase)
                        LogonModel.Databases = null;
                    else
                        LoadDatabases();
                    //LogonModel.Databases = da.GetDatabases(LogonModel.SelectedOdbcSource, LogonModel.User, LogonModel.Password);
                    break;
            }
        }

        /// <summary>
        /// loads all databases asynchronously to prevent delays in the gui
        /// </summary>
        private void LoadDatabases()
        {
            if (_dbWorkerThread != null)
            {
                _dbWorkerThread.Abort();
                _dbWorkerThread = null;
            }

            if (LogonModel.Databases == null)
                LogonModel.Databases = new ObservableCollection<string>();

            LogonModel.Databases.Clear();

            _dbWorkerThread = new Thread(FetchDatabases);
            _dbWorkerThread.SetApartmentState(ApartmentState.STA);
            _dbWorkerThread.IsBackground = true;
            _dbWorkerThread.Start(LogonModel);
        }

        Thread _dbWorkerThread;
        /// <summary>
        /// uses a secondary thread to load the databases
        /// </summary>
        /// <param name="args"></param>
        private void FetchDatabases(object args)
        {
            var logonModel = args as LogonModel;
            if (logonModel == null)
                return;

            var service = new OdbcSourceService();
            var lst = service.GetDatabases(logonModel.SelectedOdbcSource, logonModel.User, logonModel.Password);

            if (lst == null || Parent == null)
                return;

            Parent.Dispatcher.BeginInvoke(new Action(
                    delegate()
                    {
                        foreach (var str in lst)
                        {
                            logonModel.Databases.Add(str);
                        }
                    }));
        }

        #endregion

        #region Properties

        #region Wizard

        IList<UserControl> _views;
        public IList<UserControl> Views
        {
            get
            {
                if (_views == null)
                {
                    _views = new List<UserControl>
    				         {
    				         	new WelcomeView(),
                                new LogonView
                                {
                                    DataContext = LogonModel
                                },
                                new DatabaseInfoView
                                {
                                    DataContext = LogonModel
                                },
                                StatusView,
                                new EndView(),
    				         };
                }
                return _views;
            }
        }

        UserControl _selectedView;
        public UserControl SelectedView
        {
            get
            {
                if (_selectedView == null)
                    _selectedView = Views[0];
                return _selectedView;
            }
            set
            {
                _selectedView = value;
                RaisePropertyChanged("SelectedView");
            }
        }

        public bool IsEndOfWizard
        {
            get
            {
                return SelectedView == Views[4];
            }
        }

        bool _isExecutingScripts;
        public bool IsExecutingScripts
        {
            get
            {
                return _isExecutingScripts;
            }
            set
            {
                _isExecutingScripts = value;
                RaisePropertyChanged("IsExecutingScripts");

                if (value)
                    IsScriptsExecuted = true;
            }
        }

        bool _isScriptsExecuted;
        public bool IsScriptsExecuted
        {
            get
            {
                return _isScriptsExecuted;
            }
            set
            {
                _isScriptsExecuted = value;
            }
        }

        bool _startPersonalplanerOnClose = true;
        public bool StartPersonalplanerOnClose
        {
            get
            {
                return _startPersonalplanerOnClose;
            }
            set
            {
                _startPersonalplanerOnClose = value;
                RaisePropertyChanged("StartPersonalplanerOnClose");
            }
        }

        #endregion

        #region Models

        StatusView _statusView;
        protected StatusView StatusView
        {
            get
            {
                if (_statusView == null)
                    _statusView = new views.StatusView();
                return _statusView;
            }
        }

        LogonModel _logonModel;
        public LogonModel LogonModel
        {
            get
            {
                if (_logonModel == null)
                {
                    var da = GetService<IOdbcSourceService, OdbcSourceService>();
                    _logonModel = new LogonModel();

                    _logonModel.OdbcSources = da.GetOdbcSources();
                    LoadDatabases();

                    _logonModel.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(LogonModelPropertyChanged);
                }
                return _logonModel;
            }
        }

        #endregion 

        #endregion
    }
}
